﻿using System;
using System.Linq;
using Garfield.Core.Runtime;
using PicoContainer;
using PicoContainer.Defaults;

namespace Garfield.Runtime.Pico
{
    class ExtensionPoint
    {
        private readonly IMutablePicoContainer container;

        public ExtensionPoint(IMutablePicoContainer container)
        {
            this.container = container;
        }

        public T[] GetExtensionIdentifiers<T>()
        {
            return container.ComponentAdapters.Cast<IComponentAdapter>().Select(adapter => (T) adapter.ComponentKey).ToArray();
        }

        public T[] GetExtensions<T>()
        {
            return container.ComponentInstances.Cast<T>().ToArray();
        }

        public T GetExtension<T>(object extensionIdentifier)
        {
            return (T) container.GetComponentInstance(extensionIdentifier);
        }

        internal void RegisterExtension(object identifier, object instance)
        {
            container.RegisterComponentInstance(identifier, instance);
        }

        internal void RegisterExtension(object identifier, Type implementation, Delegate initializer)
        {
            container.RegisterComponentImplementation(identifier, implementation);
            var adapter = container.GetComponentAdapter(identifier);
            if (adapter is CachingComponentAdapter)
            {
                adapter = ((CachingComponentAdapter) adapter).Delegate;
            }
            ((ComponentAdapter) adapter).Initializer = initializer;
        }
    }

    class ExtensionPoint<ExtensionType> : ExtensionPoint, IExtensionPoint<ExtensionType>
    {
        public ExtensionPoint(IMutablePicoContainer container)
            : base(container)
        {
        }

        public ExtensionType[] Extensions
        {
            get { return GetExtensions<ExtensionType>(); }
        }
    }

    class ExtensionPoint<ExtensionIdentifierType, ExtensionType> : ExtensionPoint, IExtensionPoint<ExtensionIdentifierType, ExtensionType>
    {
        public ExtensionPoint(IMutablePicoContainer container)
            : base(container)
        {
        }

        public ExtensionType[] Extensions
        {
            get { return GetExtensions<ExtensionType>(); }
        }

        public ExtensionIdentifierType[] ExtensionIdentifiers
        {
            get { return GetExtensionIdentifiers<ExtensionIdentifierType>(); }
        }

        public ExtensionType GetExtension(ExtensionIdentifierType extensionIdentifier)
        {
            return GetExtension<ExtensionType>(extensionIdentifier);
        }
    }
}
